package cn.iocoder.yudao.module.pay.service.paycollectorder;

import cn.hutool.core.lang.Assert;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.enums.pay.AuditStatusEnum;
import cn.iocoder.yudao.framework.common.enums.pay.PayCollectOrderTypeEnum;
import cn.iocoder.yudao.framework.common.enums.pay.PayWalletTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
import cn.iocoder.yudao.module.pay.controller.admin.collect.vo.PayCollectOrderPageReqVO;
import cn.iocoder.yudao.module.pay.controller.admin.collect.vo.PayCollectOrderSaveReqVO;
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitReqVO;
import cn.iocoder.yudao.module.pay.controller.app.collect.vo.AppPayCollectOrderSaveReqVO;
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDetailDO;
import cn.iocoder.yudao.module.pay.dal.dataobject.paycollectorder.PayCollectOrderDO;
import cn.iocoder.yudao.module.pay.dal.mysql.paycollectorder.PayCollectOrderMapper;
import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO;
import cn.iocoder.yudao.module.pay.framework.pay.core.WalletPayClient;
import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
import cn.iocoder.yudao.module.pay.service.wallet.PayWalletService;
import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi;
import com.google.common.collect.Maps;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Map;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.*;
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.COLLECT_ORDER_NOT_EXISTS;

/**
 * 收款订单 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
public class PayCollectOrderServiceImpl implements PayCollectOrderService {

    @Resource
    private PayCollectOrderMapper collectOrderMapper;
    @Resource
    private PayWalletService payWalletService;
    @Resource
    private PayNoRedisDAO payNoRedisDAO;
    @Resource
    @Lazy
    private TradeOrderApi tradeOrderApi;
    @Resource
    @Lazy
    private PayOrderService payOrderService;
    @Resource
    @Lazy
    private MemberUserApi memberUserApi;

    @Override
    @Transactional
    public Long createCollectOrder(AppPayCollectOrderSaveReqVO createReqVO) {
        memberUserApi.validateUserStatus(getLoginUserId());

        // 插入
        PayCollectOrderDO collectOrder = BeanUtils.toBean(createReqVO, PayCollectOrderDO.class);
        if (PayCollectOrderTypeEnum.PAYMENT.getType().equals(collectOrder.getType())) {
            Assert.notNull(collectOrder.getPayOrderNo(), "货款支付,支付单号不能为空");
            // 货款支付 校验支付单
            PayOrderDO payOrder = payOrderService.getOrder(Long.valueOf(collectOrder.getPayOrderNo()));
            Assert.notNull(payOrder, "货款支付,支付单不存在");
            payOrderService.updatePayOrderByCollectCreat(payOrder.getId());
            tradeOrderApi.updateOrderByCreatePayCheck(Long.valueOf(collectOrder.getPayOrderNo()));
        }
        collectOrder.setOrderNo(payNoRedisDAO.generate(PayNoRedisDAO.COLLECT_ORDER_NO_PREFIX));
        collectOrder.setUserId(getLoginUserId());
        collectOrder.setUserName(getLoginUserName());
        collectOrderMapper.insert(collectOrder);



        // 返回
        return collectOrder.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void checkCollectOrder(PayCollectOrderSaveReqVO updateReqVO) {
        // 校验存在
        PayCollectOrderDO order = validateCollectOrderExists(updateReqVO.getId());
        PayOrderDO payOrder = null;
        PayOrderDetailDO payDetail = null;

        if (PayCollectOrderTypeEnum.PAYMENT.getType().equals(order.getType())) {
            // 货款支付 校验支付单
            payOrder = payOrderService.getOrder(Long.valueOf(order.getPayOrderNo()));
            Assert.notNull(payOrder, "货款支付,支付单不存在");
            payDetail = payOrderService.getWaitingPayByPayOrder(payOrder.getId());
            Assert.notNull(payDetail, "货款支付,待支付单不存在");
        }

        order.setCollectInfoId(updateReqVO.getCollectInfoId());
        order.setActualAmount(updateReqVO.getActualAmount());
        order.setFee(BigDecimal.ZERO);
        order.setStatus(updateReqVO.getStatus());
        order.setAuditAdminId(getLoginUserId());
        order.setAuditAdminName(getLoginUserNickname());
        order.setAuditReason(updateReqVO.getAuditReason());
        order.setAuditTime(LocalDateTime.now());
        order.setUpdateTime(LocalDateTime.now());
        order.setUpdater(String.valueOf(getLoginUserId()));
        collectOrderMapper.updateById(order);

        // 审核通过-更新钱包
        if (PayCollectOrderTypeEnum.WALLET_RECHARGE.getType().equals(order.getType())) {
            if (AuditStatusEnum.APPROVED.getStatus().equals(order.getStatus())) {
            payWalletService.addBalanceByCollect(updateReqVO.getUserId(), String.valueOf(updateReqVO.getId()),
                    updateReqVO.getActualAmount(), PayWalletTypeEnum.RMB);
            } else {
                payWalletService.createTransactionByCollectCheckFailed(updateReqVO.getUserId(),updateReqVO.getOrderNo(), PayWalletTypeEnum.RMB);
            }
        }
        // 货款支付审核通过 调用支付接口对支付单 进行支付
        else if (PayCollectOrderTypeEnum.PAYMENT.getType().equals(order.getType())) {
            if (AuditStatusEnum.APPROVED.getStatus().equals(order.getStatus())) {
                PayOrderSubmitReqVO reqVO = new PayOrderSubmitReqVO();
                reqVO.setId(payDetail.getId());
                reqVO.setPayOrderId(payOrder.getId());
                reqVO.setChannelCode(PayChannelEnum.SPEC.getCode());
                reqVO.setReturnUrl(payOrder.getNotifyUrl());
                reqVO.setCheckResult(true);
                reqVO.setPayPicUrl(order.getPayPicUrl());
                Map<String, String> channelExtras = Maps.newHashMapWithExpectedSize(2);
                channelExtras.put(WalletPayClient.USER_ID_KEY, String.valueOf(order.getUserId()));
                channelExtras.put(WalletPayClient.USER_TYPE_KEY, String.valueOf(UserTypeEnum.MEMBER_PERSON.getValue()));
                reqVO.setChannelExtras(channelExtras);
                payOrderService.submitOrder(reqVO, getClientIP());
            } else if (AuditStatusEnum.REJECTED.getStatus().equals(order.getStatus())){
                payOrderService.updatePayOrderByCollectRejected(payOrder.getId());
                tradeOrderApi.updateOrderByCollectRejected(payOrder.getId());
            }
        }


    }

    @Override
    public void deleteCollectOrder(Long id) {
        // 校验存在
        validateCollectOrderExists(id);
        // 删除
        collectOrderMapper.deleteById(id);
    }

    private PayCollectOrderDO validateCollectOrderExists(Long id) {
        PayCollectOrderDO collectOrderDO = collectOrderMapper.selectById(id);
        if (collectOrderDO == null) {
            throw exception(COLLECT_ORDER_NOT_EXISTS);
        }
        return collectOrderDO;
    }

    @Override
    public PayCollectOrderDO getCollectOrder(Long id) {
        return collectOrderMapper.selectById(id);
    }

    @Override
    public PageResult<PayCollectOrderDO> getCollectOrderPage(PayCollectOrderPageReqVO pageReqVO) {
        return collectOrderMapper.selectPage(pageReqVO);
    }

    @Override
    public void createCollectOrderAuto(PayCollectOrderDO orderDO) {
        collectOrderMapper.insert(orderDO);
    }

    @Override
    public PayCollectOrderDO getCollectOrderByOrderNo(String orderNo) {
        PayOrderDO payOrderDO = payOrderService.getOrderByOrderNo(orderNo);
        return collectOrderMapper.getCollectOrderByPayId(payOrderDO.getId());
    }

}